package ai.ann.image.trainer.gui;

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Checkbox;
import java.awt.Choice;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.List;
import java.awt.Panel;
import java.awt.ScrollPane;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;

import ai.ann.NeuralNetwork;
import ai.ann.NeuralNetworkFactory;
import ai.ann.Property;
import ai.ann.image.trainer.ColorFactory;

import util.essential.SourceGetter;
import util.essential.VariableValueGetter;

/**
 * @author alexis
 *
 */
public class TrainingExtractorGUI extends Frame implements InformationListener{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	//Constants:
	private static final VariableValueGetter valueGetter = new VariableValueGetter(Property.CONFIGURATION_FILE_NAME);
	private final byte TEXT_LENGTH = Byte.valueOf(TrainingExtractorGUI.valueGetter.getStringValue("text_length")).byteValue();
	private final byte MATRIX_REPRESENTATION_SIZE = Byte.valueOf(TrainingExtractorGUI.valueGetter.getStringValue("matrix_representation_size")).byteValue();
	private final Dimension FRAME_SIZE = new Dimension(Integer.parseInt(TrainingExtractorGUI.valueGetter.getStringValue("frame_width")),Integer.parseInt(TrainingExtractorGUI.valueGetter.getStringValue("frame_height")));
	private final String SEPARATOR = TrainingExtractorGUI.valueGetter.getStringValue("separator");//";";
	private final String IMAGE_FILES_BASE_PATH = TrainingExtractorGUI.valueGetter.getStringValue("image_files_base_path");
	private final String PATTERN_FILES_BASE_PATH = TrainingExtractorGUI.valueGetter.getStringValue("pattern_files_base_path");
	//Attributes:
	private Label position_Lbl,informative_Lbl;
	private ImageComponent image;
	private ColorMatrixComponent colorMatrixComponent;
	private TextField 	imageFilePath_TF,
						patternFilePath_TF;
	private List patterList_Lst;
	private Choice fileList_Ch;
	private Checkbox[]checkboxs;

	private Button delete,clearAll,save;
	//Constructor:
	public TrainingExtractorGUI(){
		super("TrainingExtractor 0.2 - "+valueGetter.getStringValue("taste_size")+"x"+valueGetter.getStringValue("taste_size")+" Matrix Size - "+TrainingExtractorGUI.valueGetter.getStringValue("color_space")+" Color Space");
		this.init();
		this.pack();
		this.setVisible(true);
	}
	//Methods:
	private void init(){
		Panel mainPanel = new Panel();
		mainPanel.setLayout(new GridLayout(1,2));
		mainPanel.add(this.getImagePresentationPanel());
		mainPanel.add(this.getControlPanel());
		this.setLayout(new BorderLayout());
		this.add(mainPanel,BorderLayout.SOUTH);
		this.informative_Lbl = new Label("...");
		this.add(this.informative_Lbl,BorderLayout.NORTH);
		this.addWindowListener(new WindowAdapter() {
		
			public void windowClosing(WindowEvent arg0) {
				super.windowClosing(arg0);
				System.exit(0);
			}
		
		});
		
	}
	private Component getControlPanel() {
		Panel p = new Panel();
		p.setLayout(new BorderLayout());
		p.add(this.getImageLoaderPanel(),BorderLayout.NORTH);
		p.add(this.getPatterValuerPanel(),BorderLayout.CENTER);
		p.add(this.getPatterListManagerPanel(),BorderLayout.SOUTH);
		return p;
	}
	private Component getPatterListManagerPanel() {
		Panel p = new Panel();
		p.setLayout(new BorderLayout());
		p.add(this.getPatternFilePathPanel(),BorderLayout.NORTH);
		this.patterList_Lst = new List();//List(this.TEXT_LENGTH);
		this.patterList_Lst.addItemListener(new ItemListener() {
			public void itemStateChanged(ItemEvent arg0) {
				msg("Showing color matrix representation...");
				String tmp = patterList_Lst.getSelectedItem();
				//System.out.println(">   "+tmp);
				String[]token = tmp.split(SEPARATOR);
				Color[][]color=new Color[ColorMatrixComponent.HEIGHT_SIZE][ColorMatrixComponent.WIDTH_SIZE];
				for (int i = 0, h = 0; i < color.length; i++) {
					for (int j = 0; j < color[i].length; j++) {
						if(h<(token.length-NeuralNetwork.NUMBER_OF_OUTPUTS)){
							//TODO: Here is possible to apply the g(x) functino.
							long[]transformedColor = ColorFactory.transformeFrom(Float.parseFloat(token[h]),Float.parseFloat(token[h+1]),Float.parseFloat(token[h+2]));
							/*
							System.out.println("Color = "+transformedColor[0]+", "+transformedColor[1]+", "+transformedColor[2]);
							/**/
							color[i][j]=new Color((int)transformedColor[0],(int)transformedColor[1],(int)transformedColor[2]);
							h+=((NeuralNetwork.WITH_ILUMINATION_CHANNEL)?(NeuralNetwork.INPUT_CHANNELS+1):NeuralNetwork.INPUT_CHANNELS);
						}else{
							i = color.length;//Finish...
							break;
						}
					}
				}
				colorMatrixComponent.setColorMatrix(color);
			}
		});
		p.add(this.patterList_Lst,BorderLayout.CENTER);
		p.add(this.getPatternListButtonManagerPanel(),BorderLayout.SOUTH);
		return p;
	}
	private Component getPatternListButtonManagerPanel() {
		Panel p = new Panel();
		p.setLayout(new FlowLayout());
		this.delete=new Button("Delete");
		this.clearAll=new Button("Clear All");
		this.save=new Button("Save");
		p.add(this.delete);
		this.delete.addActionListener(new ActionListener() {
		
			public void actionPerformed(ActionEvent arg0) {
				patterList_Lst.remove(patterList_Lst.getSelectedIndex());
				msg("Pattern has been removed.");
			}
		
		});
		this.clearAll.addActionListener(new ActionListener() {
		
			public void actionPerformed(ActionEvent arg0) {
				patterList_Lst.removeAll();
				image.clearShapeList();
				msg("List was clean.");
			}
		
		});
		p.add(this.clearAll);
		Button loadPathFile = new Button("Load");
		loadPathFile.addActionListener(new ActionListener() {
		
			public void actionPerformed(ActionEvent arg0) {
				String tmp = patternFilePath_TF.getText();
				if(tmp!=null&&tmp.length()>0){
					patterList_Lst.removeAll();
					clearColorMatrix();
					for (Iterator iter = SourceGetter.config.getSource(tmp).iterator(); iter.hasNext();) {
						String element = iter.next().toString();
						patterList_Lst.add(element);
					}
				}else{
					msg("No pattern file name!!!");
				}
			}
		
		});
		p.add(loadPathFile);
		this.save.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent arg0) {
				String fileName = patternFilePath_TF.getText();
				if(fileName!=null&&!fileName.isEmpty()){
					String[] tmp = patterList_Lst.getItems();
					StringBuffer str = new StringBuffer();
					for (int i = 0; i < tmp.length; i++) {
						str.append(tmp[i]+(((i+1)!=tmp.length)?"\n":""));
					}
					if(SourceGetter.config.replaceTextFile(fileName, str.toString())){
						msg("File \""+fileName+"\" was saved.");
					}else{
						msg("Can't save file \""+fileName+"\"!");
					}
					
				}
			}
		
		});
		p.add(this.save);
		Button toTrainNeuralNetwork = new Button("NN Trainning");
		toTrainNeuralNetwork.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				setEnabledGUI(false);
				msg("Trainning...");
				try {
					/*
					String 	path = patternFilePath_TF.getText(),
							inputRowSelector = "1-"+NeuralNetwork.INPUT_NEURON_NUMBER,
							trainningRowSelector = String.valueOf(NeuralNetwork.INPUT_NEURON_NUMBER+NeuralNetwork.NUMBER_OF_OUTPUTS),
							outputFileName = "";
					int 	amountTrainningPatherns = SourceGetter.getSource(patternFilePath_TF.getText()).size(),
							cicles = 2000;
					System.out.println(	"* Input File = "+path+"\n"+
										"* Input Row Selector = "+inputRowSelector+"\n"+
										"* Trainning Row Selector = "+trainningRowSelector+"\n"+
										"* Output File Name = "+outputFileName+"\n"+
										"* Amount Trainning Patherns = "+amountTrainningPatherns+"\n"+
										"* Clicles = "+cicles+"\n"+
										"* With Ilumination Channel = "+NeuralNetwork.WITH_ILUMINATION_CHANNEL+"\n"+
										"* Input Channels = "+NeuralNetwork.INPUT_CHANNELS);
					/**/
					NeuralNetworkFactory.trainning(patternFilePath_TF.getText(),
						    				"1-"+NeuralNetwork.INPUT_NEURON_NUMBER,
						    				String.valueOf(NeuralNetwork.INPUT_NEURON_NUMBER+1)+
						    				((NeuralNetwork.NUMBER_OF_OUTPUTS>1)?
										    ("-"+String.valueOf(NeuralNetwork.INPUT_NEURON_NUMBER+NeuralNetwork.NUMBER_OF_OUTPUTS)):
										    	""),
										    "",SourceGetter.config.getSource(patternFilePath_TF.getText()).size(),2000);
					setEnabledGUI(true);
					msg("Trainning is ready! ("+patterList_Lst.getItemCount()+" patterns; "+NeuralNetwork.INPUT_NEURON_NUMBER+" inputs; "+NeuralNetwork.NUMBER_OF_OUTPUTS+" outputs)");
				} catch (IOException e) {
					e.printStackTrace();
					setEnabledGUI(true);
					msg("Trainning error!!!");
					
				}
			}
		});
		p.add(toTrainNeuralNetwork);
		return p;
	}
	private void setEnabledGUI(boolean availability){
		this.setEnabled(availability);
	}
	private Component getPatternFilePathPanel() {
		Panel p = new Panel();
		p.setLayout(new BorderLayout());
		p.add(new Label("Pattern File Name:"),BorderLayout.NORTH);
		this.patternFilePath_TF = new TextField(this.TEXT_LENGTH);
		this.patternFilePath_TF.setText(this.PATTERN_FILES_BASE_PATH);
		p.add(this.patternFilePath_TF,BorderLayout.CENTER);
		return p;
	}
	private Component getPatterValuerPanel() {
		Panel p = new Panel();
		p.setLayout(new BorderLayout());
		p.add(this.getOutputPatternValueGenerator(),BorderLayout.NORTH);
		p.add(this.getPatterRepresentationPanel(),BorderLayout.SOUTH);
		return p;
	}
	private Component getOutputPatternValueGenerator() {
		Panel p = new Panel(),p2 = new Panel();
		p.setLayout(new FlowLayout());
		p.add(new Label("Pattern Value: "));
		//CheckboxGroup cbg = new CheckboxGroup();
		this.checkboxs = new Checkbox[NeuralNetwork.NUMBER_OF_OUTPUTS];
		for (int i = 0; i < this.checkboxs.length; i++) {
			//this.checkboxs[i]=new Checkbox("Out"+(i+1),cbg,false);			
			this.checkboxs[i]=new Checkbox("Out"+(i+1),false);
			p2.add(this.checkboxs[i]);
		}
		//if(this.checkboxs.length>0)this.checkboxs[0].setState(true);
		p.add(p2);
		Button selectAll = new Button("+"),deselectAll = new Button("-");
		selectAll.addActionListener(new ActionListener() {
		
			public void actionPerformed(ActionEvent arg0) {
				for (int i = 0; i < checkboxs.length; i++) {
					checkboxs[i].setState(true);
				}
			}
		
		});
		p.add(selectAll);
		deselectAll.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent arg0) {
				for (int i = 0; i < checkboxs.length; i++) {
					checkboxs[i].setState(false);
				}
			}
		
		});
		p.add(deselectAll);
		return p;
	}
	private Component getPatterRepresentationPanel() {
		Panel p = new Panel();
		this.colorMatrixComponent = new ColorMatrixComponent(MATRIX_REPRESENTATION_SIZE,MATRIX_REPRESENTATION_SIZE);
		p.add(this.colorMatrixComponent);
		//return this.colorMatrixComponent;
		return p;
	}
	private Component getImageLoaderPanel() {
		Panel p = new Panel(),p2 = new Panel();
		p.setLayout(new BorderLayout());
		p.add(new Label("Image File Path:"),BorderLayout.NORTH);
		this.imageFilePath_TF = new TextField(this.TEXT_LENGTH);
		this.imageFilePath_TF.setText(this.IMAGE_FILES_BASE_PATH);
		p.add(this.imageFilePath_TF,BorderLayout.CENTER);
		Button updateImages = new Button("Update List");
		this.fileList_Ch = new Choice();
		this.updateFiles(this.fileList_Ch, imageFilePath_TF.getText());
		updateImages.addActionListener(new ActionListener() {
		
			public void actionPerformed(ActionEvent arg0) {
				String imageFilePath = imageFilePath_TF.getText();
				if(imageFilePath!=null&&!imageFilePath.isEmpty()){
					updateFiles(fileList_Ch, imageFilePath);
				}
				msg("Image(s) updated.");
			}
		
		});
		p2.add(updateImages);
		this.fileList_Ch.addItemListener(new ItemListener() {
		
			public void itemStateChanged(ItemEvent arg0) {
				String imageFilePath = imageFilePath_TF.getText();
				if(imageFilePath!=null&&!imageFilePath.isEmpty()){
					//System.out.println("Loading \""+imageFilePath+"\" file image...");
					imageFilePath = (imageFilePath+((!imageFilePath.endsWith("/"))?"/":"")+fileList_Ch.getSelectedItem());
					image.loadImage(imageFilePath);
				}
				msg("Image \""+imageFilePath+"\" was loaded.");
			}
		
		});
		p2.add(this.fileList_Ch);
		p.add(p2,BorderLayout.SOUTH);
		return p;
	}
	private Component getImagePresentationPanel() {
		Panel p = new Panel();
		ScrollPane s = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
		s.setSize(this.FRAME_SIZE);
		this.image = new ImageComponent((int)this.FRAME_SIZE.getWidth(),(int)this.FRAME_SIZE.getHeight());
		this.image.addListener(this);
		s.add(this.image);
		p.setLayout(new BorderLayout());
		p.add(s, BorderLayout.NORTH);
		this.position_Lbl = new Label("Position: (x,y)");
		p.add(this.position_Lbl, BorderLayout.SOUTH);
		return p;
	}
	public void listenToInformation(InformationEvent information) {
		Color[][]colorMatrix = information.getColorMatrix();
		this.position_Lbl.setText("Position: "+information.getInformativeText());
		StringBuffer str = new StringBuffer();
		Color c; 
		for (int i = 0; i < colorMatrix.length; i++) {
			for (int j = 0; j < colorMatrix[i].length; j++) {
				c = colorMatrix[i][j];
				//TODO: Here is possible to adapt the f(x) function.
				long[]transformedColor = ColorFactory.transformeTo(c.getRed(),c.getGreen(),c.getBlue());
				for (int k = 0; k < transformedColor.length; k++) {
					str.append(transformedColor[k]+this.SEPARATOR);
				}
				//str.append(transformedColor[0]+this.SEPARATOR+transformedColor[1]+this.SEPARATOR+transformedColor[2]+this.SEPARATOR);
			}
		}
		for (int i = 0; i < this.checkboxs.length; i++) {
			str.append(((this.checkboxs[i].getState())?"1":"0")+(((i+1)<this.checkboxs.length)?this.SEPARATOR:""));
		}
		this.colorMatrixComponent.setColorMatrix(colorMatrix);
		this.patterList_Lst.add(str.toString());
		/*
		String[]tmp = str.toString().split(";");
		System.out.println("Total > "+tmp.length);
		System.out.println("Pattern > "+(tmp.length-this.NUMBER_OF_OUTPUTS));
		System.out.println("Output > "+this.NUMBER_OF_OUTPUTS);
		/**/
	}
	private void updateFiles(Choice choice, String path) {
		File file = new File(path);
		File[] tmp = file.listFiles();
		choice.removeAll();
		if(tmp!=null){
			for (int i = 0; i < tmp.length; i++) {
				if (tmp[i].getName().endsWith(".jpg")
					|| tmp[i].getName().endsWith(".JPG")
					|| tmp[i].getName().endsWith(".gif")
					|| tmp[i].getName().endsWith(".GIF")) {
					choice.add(tmp[i].getName());
				}
			}
		}
	}
	private void clearColorMatrix(){
		Color[][]color=new Color[ColorMatrixComponent.HEIGHT_SIZE][ColorMatrixComponent.WIDTH_SIZE];
		for (int i = 0; i < color.length; i++) {
			for (int j = 0; j < color[i].length; j++) {
				color[i][j] = Color.BLACK;
			}
		}
		colorMatrixComponent.setColorMatrix(color);
	}
	private void msg(String txt){
		this.informative_Lbl.setText(txt);
	}
	//Main:
	public static void main(String[]args){
		new TrainingExtractorGUI();
	}
}
